package com.gede.web.esael.Controller;

import org.ofdrw.gm.cert.PKCS12Tools;
import org.ofdrw.gm.ses.v1.SESeal;
import org.ofdrw.reader.OFDReader;
import org.ofdrw.sign.OFDSigner;
import org.ofdrw.sign.SignMode;
import org.ofdrw.sign.signContainer.SESV1Container;
import org.ofdrw.sign.signContainer.SESV4Container;
import org.ofdrw.sign.stamppos.NormalStampPos;
import org.ofdrw.sign.stamppos.RidingStampPos;
import org.ofdrw.sign.stamppos.Side;
import org.ofdrw.sign.verify.OFDValidator;
import org.ofdrw.sign.verify.container.SESV1ValidateContainer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.GeneralSecurityException;
import java.security.PrivateKey;
import java.security.cert.Certificate;

@RestController
public class OfdController {
    Logger logger = LoggerFactory.getLogger(OfdController.class);

    /**
     * @param path_out 输出位置
     * @param path_ofd 要操作的ofd文档位置
     * @param path_p12 证书位置
     * @param path_esl 电子印章信息
     * @param alias    证书别名
     * @param pwd      证书密码
     * @param page     要操作ofd文档的页码
     * @param x        签盖位置 x坐标 （左上角为原点）
     * @param y        签盖位置 y坐标 （左上角为原点）
     * @return
     */
    @PostMapping("/ofd/sesv1sign")
    public String SESV1Sign(String path_out, String path_ofd, String path_p12, String path_esl, String alias, String pwd, int page, double x, double y) {
        Path userP12Path = Paths.get(path_p12);
        Path sealPath = Paths.get(path_esl);

        PrivateKey prvKey = null;
        try {
            prvKey = PKCS12Tools.ReadPrvKey(userP12Path, alias, pwd);
        } catch (GeneralSecurityException e) {
            e.printStackTrace();
            return "7=" + e.getMessage();
        } catch (IOException e) {
            e.printStackTrace();
            return "6=" + e.getMessage();
        }
        Certificate signCert = null;
        try {
            signCert = PKCS12Tools.ReadUserCert(userP12Path, alias, pwd);
        } catch (GeneralSecurityException e) {
            e.printStackTrace();
            return "5=" + e.getMessage();
        } catch (IOException e) {
            e.printStackTrace();
            return "4=" + e.getMessage();
        }
        SESeal seal = null;
        try {
            seal = SESeal.getInstance(Files.readAllBytes(sealPath));
        } catch (IOException e) {
            e.printStackTrace();
            return "3=" + e.getMessage();
        }

        Path src = Paths.get(path_ofd);
        Path out = Paths.get(path_out);
        // 1. 构造签名引擎
        try (OFDReader reader = new OFDReader(src);
             OFDSigner signer = new OFDSigner(reader, out)
//             OFDSigner signer = new OFDSigner(reader, out, new NumberFormatAtomicSignID()
        ) {
            SESV1Container signContainer = new SESV1Container(prvKey, seal, signCert);
            // 2. 设置签名模式
//            signer.setSignMode(SignMode.WholeProtected);
            signer.setSignMode(SignMode.ContinueSign);
            // 3. 设置签名使用的扩展签名容器
            signer.setSignContainer(signContainer);
            // 4. 设置显示位置
            signer.addApPos(new NormalStampPos(page, x, y, 40, 40));
            // 5. 执行签名
            signer.exeSign();
            // 6. 关闭签名引擎，生成文档。
        } catch (GeneralSecurityException e) {
            e.printStackTrace();
            return "1=" + e.getMessage();
        } catch (IOException e) {
            e.printStackTrace();
            return "2=" + e.getMessage();
        }
        System.out.println(">> 生成文件位置: " + out.toAbsolutePath().toAbsolutePath());
        return ">> 生成文件位置: " + out.toAbsolutePath().toAbsolutePath();
    }

    /**
     * 电子签名验证引擎
     * @param url
     * @return
     */
    @PostMapping("/ofd/validate")
    public String validate(String url) {
        Path src = Paths.get(url);

        try (OFDReader reader = new OFDReader(src);
             OFDValidator validator = new OFDValidator(reader)) {
            validator.setValidator(new SESV1ValidateContainer());
            validator.exeValidate();
            System.out.println(">> 验证通过");
        } catch (IOException | GeneralSecurityException |IllegalArgumentException e) {
            e.printStackTrace();
            return e.getMessage();
        }

        return ">> 验证通过";


    }


    /**
     * @param path_out 输出位置
     * @param path_ofd 要操作的ofd文档位置
     * @param path_p12 证书位置
     * @param path_esl 电子印章信息
     * @param alias    证书别名
     * @param pwd      证书密码
     * @param side     骑缝章的位置

     * @return
     */
    @PostMapping("/ofd/sidesign")
    public String rideTop(String path_out, String path_ofd, String path_p12, String path_esl, String alias, String pwd, String side){
        Path userP12Path = Paths.get(path_p12);
        Path sealPath = Paths.get(path_esl);

        PrivateKey prvKey = null;
        Certificate signCert = null;
        org.ofdrw.gm.ses.v4.SESeal seal = null;
        try {
            prvKey = PKCS12Tools.ReadPrvKey(userP12Path, alias, pwd);
            signCert = PKCS12Tools.ReadUserCert(userP12Path, alias, pwd);
            seal = org.ofdrw.gm.ses.v4.SESeal.getInstance(Files.readAllBytes(sealPath));
        } catch (GeneralSecurityException e) {
            e.printStackTrace();
            return "1"+e.getMessage();
        } catch (IOException e) {
            e.printStackTrace();
            return "1"+e.getMessage();
        }


        Path src = Paths.get(path_ofd);
        Path out = Paths.get(path_out);
        // 1. 构造签名引擎
        try (OFDReader reader = new OFDReader(src);
             OFDSigner signer = new OFDSigner(reader, out)) {
            SESV4Container signContainer = new SESV4Container(prvKey, seal, signCert);
            // 2. 设置签名模式
            signer.setSignMode(SignMode.WholeProtected);
            // 3. 设置签名使用的扩展签名容器
            signer.setSignContainer(signContainer);
            // 4. 设置显示位置
            Side s;
            if(!side.isEmpty()&& side.equals("top")){
                s=Side.Top;
            }else if(!side.isEmpty()&& side.equals("left")){
                s=Side.Left;
            }else if(!side.isEmpty()&& side.equals("right")){
                s=Side.Right;
            }else if(!side.isEmpty()&& side.equals("bottom")){
                s=Side.Bottom;
            }else{
                return "side参数错误";
            }
            signer.addApPos(new RidingStampPos(s, 40, 40));
            // 5. 执行签名
            signer.exeSign();
            // 6. 关闭签名引擎，生成文档。
        }catch (GeneralSecurityException| IOException e){
            return "3"+e.getMessage();
        }
        System.out.println(">> 生成文件位置: " + out.toAbsolutePath().toAbsolutePath());
        return ">> 生成文件位置: " + out.toAbsolutePath().toAbsolutePath();
    }


    /**
     * @param path_out 输出位置
     * @param path_ofd 要操作的ofd文档位置
     * @param path_p12 证书位置
     * @param path_esl 电子印章信息
     * @param alias    证书别名
     * @param pwd      证书密码
     * @param page     要操作ofd文档的页码
     * @param x        签盖位置 x坐标 （左上角为原点）
     * @param y        签盖位置 y坐标 （左上角为原点）
     * @return
     */
    @PostMapping("/ofd/sesv4sign")
    public String SESV4Sign(String path_out, String path_ofd, String path_p12, String path_esl, String alias, String pwd, int page, double x, double y) throws GeneralSecurityException, IOException {
        Path userP12Path = Paths.get(path_p12);
        Path sealPath = Paths.get(path_esl);

        PrivateKey prvKey = PKCS12Tools.ReadPrvKey(userP12Path, alias, pwd);
        Certificate signCert = PKCS12Tools.ReadUserCert(userP12Path, alias, pwd);
        org.ofdrw.gm.ses.v4.SESeal seal = org.ofdrw.gm.ses.v4.SESeal.getInstance(Files.readAllBytes(sealPath));

        Path src = Paths.get(path_ofd);
        Path out = Paths.get(path_out);
        // 1. 构造签名引擎
        try (OFDReader reader = new OFDReader(src);
             OFDSigner signer = new OFDSigner(reader, out)
//             OFDSigner signer = new OFDSigner(reader, out, new NumberFormatAtomicSignID())
        ) {
            SESV4Container signContainer = new SESV4Container(prvKey, seal, signCert);
            // 2. 设置签名模式
//            signer.setSignMode(SignMode.WholeProtected);
            signer.setSignMode(SignMode.ContinueSign);
            // 3. 设置签名使用的扩展签名容器
            signer.setSignContainer(signContainer);
            // 4. 设置显示位置
            signer.addApPos(new NormalStampPos(1, 50, 50, 40, 40));
            // 5. 执行签名
            signer.exeSign();
            // 6. 关闭签名引擎，生成文档。
        }
        System.out.println(">> 生成文件位置: " + out.toAbsolutePath().toAbsolutePath());
        return ">> 生成文件位置: " + out.toAbsolutePath().toAbsolutePath();
    }
}